Building Our Way to Affordability: A YIMBY Policy Analysis
Author
Shreya Karki
Published
November 24, 2025
1 Introduction
Housing affordability is one of America’s most pressing urban challenges. This analysis identifies the nation’s most pro-housing metropolitan areas by examining construction patterns, economic opportunity, and housing costs across Core-Based Statistical Areas.
Following the YIMBY idea that permissive zoning and increased housing supply can reduce costs and support more dynamic, inclusive communities, we assess which regions are building enough homes to meet demand and which are falling behind.
2 Data Relationship Diagram
TipKey Data Relationships
All ACS tables (INCOME, RENT, POPULATION, HOUSEHOLDS) share the composite key GEOID + year.
PERMITS uses CBSA, which corresponds to ACS GEOID, joins on geography + year.
WAGES uses BLS industry codes (e.g., 101, 1011) that approximate but do not exactly match NAICS in INDUSTRY_CODES; this link is conceptual.
WAGES connects to ACS and PERMITS after transforming CBSA → “C” + first 4 digits (e.g., 10180 → C1018).
For clarity, not every possible line is drawn — the diagram shows only the primary joins used in analysis.
This ERD was created in dbdiagram.io and embedded as an SVG for best visual clarity.
3 Construction Leadership & Housing Supply Analysis (Data Exploration)
3.1 National Housing Production Leaders: 2010-2019
Code
# Identify metropolitan areas with highest housing productiontop_housing_metros <-inner_join(PERMITS, INCOME, join_by(CBSA == GEOID), suffix =c("_permits", "_income")) |>filter(year_permits >=2010, year_permits <=2019) |>group_by(NAME) |>summarise(total_units =sum(new_housing_units_permitted, na.rm =TRUE)) |>arrange(desc(total_units)) |>slice_max(total_units, n =1) |>ungroup()
The Dallas-Fort Worth-Arlington, TX Metro Area metropolitan area permitted 6,451,564 new housing units from 2010-2019, demonstrating the scale achievable under pro-housing policies. This level of production represents a benchmark for regional housing growth targets.
3.2 Market Volatility Analysis: Albuquerque Case Study
Table: Annual Housing Production — Albuquerque Metro Area
Code
library(DT)# Analyze construction patterns in a mid-sized metroalbuquerque_construction <- PERMITS |>filter(CBSA ==10740) |>group_by(year) |>summarise(`Housing Units Permitted`=sum(new_housing_units_permitted, na.rm =TRUE)) |>arrange(year)datatable( albuquerque_construction,caption ='Annual Housing Production: Albuquerque Metropolitan Area',options =list(pageLength =10, searching =FALSE))
Albuquerque’s housing permits peaked in 2021, with the highest pre-pandemic level recorded in 2013.
Interpretation: This pattern shows a brief spike rather than a steady climb. To judge local homebuilding capacity, it is better to look at multi-year trajectories than any single high point.
3.3 Regional Income Distribution Patterns
Code
# filter year income_2015 <- INCOME |>filter(year ==2015)# inner-join tables and create a new column income_2015 <- income_2015 |>inner_join(HOUSEHOLDS, by =c("GEOID", "year")) |>inner_join(POPULATION, by =c("GEOID", "year")) |>select(GEOID, NAME, year, household_income, households, population) |>mutate(total_income_cbsa = household_income * households,state =str_extract(NAME, ", (.{2})", group =1))# state with highest average individual incometop_state_income <- income_2015 |>group_by(state) |>summarise(total_income_state =sum(total_income_cbsa, na.rm =TRUE),total_population_state =sum(population, na.rm =TRUE)) |>mutate(avg_individual_income = total_income_state / total_population_state) |>arrange(desc(avg_individual_income)) |>slice_max(avg_individual_income, n =1)
In DC, the average individual income was the highest in 2015 at approximately $33,233 per person.
Interpretation: High income alone does not ensure affordability. Without enough housing, rents rise faster than wages.
3.4 High-Skill Employment Distribution
Code
# Filter WAGES for data scientists (NAICS 5182)Data_scientist <- WAGES |>filter(INDUSTRY ==5182) |>select(YEAR, FIPS, EMPLOYMENT, AVG_WAGE) |>mutate(std_cbsa =paste0(FIPS, "0"))# Prepare POPULATION table for joining (to get CBSA names)POP_join <- POPULATION |>mutate(std_cbsa =paste0("C", GEOID)) |>select(std_cbsa, NAME, year)# Join to find which CBSA had the most data scientists each yeards_named <- Data_scientist |>inner_join(POP_join, by =join_by(std_cbsa, YEAR == year)) |>group_by(YEAR, NAME) |>summarise(EMPLOYMENT =sum(EMPLOYMENT, na.rm =TRUE)) |>slice_max(EMPLOYMENT, n =1) |>arrange(YEAR)
In the latest year (2023), San Francisco-Oakland-Fremont, CA Metro Area has the most data scientists. New York–Newark–Jersey City last held the top spot in 2015.
Interpretation: Fast growth in high-paying tech jobs raises housing demand. Cities that permit new homes steadily can prevent rent spikes as their job markets expand.
3.5 Financial Sector Concentration: NYC Case Study
Code
# Filter NYC CBSA (find name containing "New York")NYC_wages <- WAGES |>mutate(std_cbsa =paste0(FIPS, "0")) |>inner_join(POPULATION |>mutate(std_cbsa =paste0("C", GEOID)) |>select(std_cbsa, NAME),by ="std_cbsa") |>filter(str_detect(NAME, "New York"))# Total wages in NYC by yearnyc_total <- NYC_wages |>group_by(YEAR) |>summarise(total_wages =sum(TOTAL_WAGES, na.rm =TRUE))# Finance & Insurance wages (NAICS 52) in NYC by yearnyc_fin <- NYC_wages |>filter(INDUSTRY ==52) |>group_by(YEAR) |>summarise(finance_wages =sum(TOTAL_WAGES, na.rm =TRUE))# Combine and calculate the fractionnyc_share <-left_join(nyc_total, nyc_fin, by ="YEAR") |>mutate(finance_share = finance_wages / total_wages)# year when the share peakednyc_share |>slice_max(finance_share, n =1)
# A tibble: 1 × 4
YEAR total_wages finance_wages finance_share
<dbl> <dbl> <dbl> <dbl>
1 2014 3.62e13 1667478619954 0.0460
Code
nyc_share_peak <- nyc_share |>slice_max(finance_share, n =1)
In the New York City CBSA, workers employed in the Finance and Insurance industries (NAICS 52) earned about 4.6% of all wages.
This share peaked in 2014, showing how important finance remains to NYC’s economy.
Interpretation: Finance jobs bring high wages, but without new housing construction, those wage gains mostly raise rents instead of improving overall affordability.
library(ggplot2)# Examine fundamental housing cost relationshipmetro_affordability_2009 <- RENT |>filter(year ==2009) |>inner_join(INCOME |>filter(year ==2009), by =c("GEOID", "year", "NAME"))ggplot(metro_affordability_2009, aes(x = household_income, y = monthly_rent)) +geom_point(color ="#2E86AB", alpha =0.5, size =2) +geom_smooth(method ="lm", color ="#C70039", linewidth =1, se =FALSE) +labs(title ="Metropolitan Housing Costs Relative to Income (2009)",subtitle ="Each point represents one metro area in the U.S.",x ="Average Household Income (USD)",y ="Median Monthly Rent (USD)", ) +scale_x_continuous(labels = scales::dollar_format()) +scale_y_continuous(labels = scales::dollar_format()) +theme_minimal(base_size =14) +theme(plot.title =element_text(face ="bold"),plot.subtitle =element_text(size =11, color ="gray40"),plot.caption =element_text(size =9, hjust =0),panel.grid.minor =element_blank() )
Rents generally increase as household income rises, but the steepness of the line shows how strongly income growth affects housing costs.
Metro areas that allow more construction (YIMBY-friendly) often fall below the trend line, meaning residents there get more housing for the same income level. This suggests that expanding housing supply can make cities more affordable even as incomes rise.
4.2 Employment-Housing Balance Trends
Code
# Analyze relationship between job growth and sectoral employmenthealthcare_employment_relationship <- WAGES |>group_by(FIPS, YEAR) |>summarise(total_employment =sum(EMPLOYMENT, na.rm =TRUE) /1000,healthcare_employment =sum(EMPLOYMENT[INDUSTRY ==62], na.rm =TRUE) /1000,.groups ="drop")# Calculate median healthcare share across all metros/years (for dashed line)med_share <- healthcare_employment_relationship |>filter(total_employment >0, !is.na(total_employment), !is.na(healthcare_employment)) |>mutate(ratio = healthcare_employment / total_employment) |>summarise(median_ratio =median(ratio, na.rm =TRUE)) |>pull(median_ratio)library(ggplot2)ggplot(healthcare_employment_relationship,aes(x = total_employment, y = healthcare_employment, color =as.factor(YEAR))) +geom_point(alpha =0.5, size =2) +geom_smooth(method ="lm", color ="#C70039", linewidth =1, se =FALSE) +geom_abline(intercept =0, slope = med_share, linetype ="dashed", color ="gray40") +labs(title ="Healthcare Employment vs. Total Employment (2009–2023)",subtitle ="Each point represents one metro area; dashed line shows median healthcare share",x ="Total Employment (thousands)",y ="Healthcare Employment (thousands)",color ="Year") +theme_minimal(base_size =14) +theme(plot.title =element_text(face ="bold"),plot.subtitle =element_text(size =11, color ="gray40"),legend.position ="bottom",panel.grid.minor =element_blank())
As total employment grows, healthcare jobs rise almost proportionally. Cities with rapid job growth must ensure sufficient housing so nurses and care workers can live where they work.
4.3 Demographic Shifts & Housing Demand
Code
library(gghighlight)# Calculate household size for each metrohousehold_trends <- POPULATION |>inner_join(HOUSEHOLDS, by =c("GEOID", "year", "NAME")) |>mutate(household_size = population / households)# Identify NYC and LA correctlyunique_names <-unique(household_trends$NAME)nyc_name <- unique_names[grep("New York", unique_names)][1]la_name <- unique_names[grep("Los Angeles", unique_names)][1]# Plot with consistent formattingggplot(household_trends, aes(x = year, y = household_size, group = NAME, color = NAME)) +geom_line(alpha =0.4, linewidth =1) +gghighlight(NAME %in%c(nyc_name, la_name), use_direct_label =TRUE) +labs(title ="Average Household Size Over Time (2009–2023)",subtitle ="NYC and LA highlighted; smaller households increase housing demand",x ="Year",y ="Average Household Size",color ="Metro Area") +theme_minimal(base_size =14) +theme(plot.title =element_text(face ="bold"),plot.subtitle =element_text(size =11, color ="gray40"),legend.position ="bottom",panel.grid.minor =element_blank())
As average household size slowly declines, the same number of people need more homes. NYC and LA already have smaller households, so they must add more units per 1,000 residents to keep rent burden from rising.
Rent burden measures the share of household income spent on rent — a direct indicator of housing affordability.
The INCOME and RENT tables are joined by geography and year to compute:
To make comparisons meaningful across regions and years, the metric is standardized so that 0 = lowest and 100 = highest rent burden observed in the study period.
5.1 New York Metropolitan Area: Affordability Trends
Table: NYC Rent Burden Over Time (2009–2023)
Code
nyc_rent_burden <- rent_burden_data |>filter(City_Name =="New York-Newark-Jersey City, NY-NJ-PA Metro Area") |>arrange(year) |>select(Year = year,`Monthly Rent`= monthly_rent,`Household Income`= household_income,`Rent Burden %`= rent_burden_percent,`Burden Score`= burden_score ) |>mutate(`Monthly Rent`=round(`Monthly Rent`, 0),`Household Income`=round(`Household Income`, 0),`Rent Burden %`=round(`Rent Burden %`, 1),`Burden Score`=round(`Burden Score`, 1) )datatable( nyc_rent_burden,caption ="New York City Rent Burden Over Time (2009-2023)",options =list(pageLength =10, searching =FALSE))
Code
# Calculate the values for the policy insightnyc_first_income <- nyc_rent_burden$`Household Income`[1]nyc_last_income <- nyc_rent_burden$`Household Income`[nrow(nyc_rent_burden)]nyc_avg_burden <-round(mean(nyc_rent_burden$`Rent Burden %`), 1)
Interpretation: NYC’s rent burden stayed within a narrow range (21.4–22.9%) even as median household income rose from $65,786 to $91,562.
This shows that housing costs rose in step with earnings, leaving affordability largely unchanged. The most likely reason is a supply constraint, when demand expands but new housing does not keep pace, rent burden tends to stay flat or even rise.
Interpretation: Clearlake, CA Micro Area faces the highest rent burden in the latest year, with residents spending about 31.2% of income on rent (standardized score 72.9).
This indicates acute affordability pressure, consistent with demand outpacing new supply. These metros are strong candidates for targeted permitting reforms and federal YIMBY incentives to expand rental stock quickly.
Interpretation: Laconia, NH Micro Area indicates the lowest rent burden in the latest year, with residents spending about 12.7% of income on rent and a standardized score of 1.6.
This outcome is consistent with ample new supply and/or strong income growth, suggesting that steady permitting and streamlined approvals can keep housing costs in check.
6 Housing Growth: Measuring Supply Responsiveness
Housing growth captures how effectively cities add homes to match demand.
Using permit and population data, two complementary indicators were developed:
- an instantaneous production metric, measuring new housing relative to population size; and
- a rate-based growth metric, comparing permitting to five-year population change.
Combining these yields a composite housing growth score, which highlights metros that are both building actively and scaling with demographic trends.
Interpretation: Springfield, OH Metro Area demonstrates the most balanced housing response to population expansion, with a five-year growth-adjusted score of 7.7.
This means that new housing supply has kept pace with rapid population increases—an indicator of adaptive land-use policy and capacity planning that maintains affordability while accommodating in-migration.
Metros with low growth scores, by contrast, risk rising rent burdens as population outstrips new construction.
Interpretation: Punta Gorda, FL Metro Area leads the nation with an overall housing growth score of 28.6, balancing both strong construction volume and responsiveness to local population changes.
This composite result highlights how consistent permitting pipelines and pro-housing zoning frameworks can deliver stability across economic cycles.
Such metros illustrate the potential impact of federal-state collaboration on long-term housing affordability.
6.3.1 Policy Takeaway
Regions like Punta Gorda, FL Metro Area and Springfield, OH Metro Area show that consistent, multi-year housing production, most effectively keeps rent burdens stable.
Federal programs that reward steady permitting and year-over-year delivery can replicate this success across other metros.
7 Visualization
Code
# Join rent burden and housing growth datasetsyimby_base <- rent_burden_data |>inner_join(housing_growth_data, by =c("City_Name"="NAME", "year")) |>select(City_Name, year, rent_burden_percent, burden_score,population, pop_5yr_growth, composite_score)# Calculate rent burden change, population growth, and housing growthyimby_metrics <- yimby_base |>group_by(City_Name) |>mutate(early_burden =mean(rent_burden_percent[year <=2015], na.rm =TRUE),recent_burden =mean(rent_burden_percent[year >=2020], na.rm =TRUE),burden_change = recent_burden - early_burden,pop_growth = (max(population, na.rm =TRUE) -min(population, na.rm =TRUE)) /min(population, na.rm =TRUE) *100,avg_housing_growth =mean(composite_score, na.rm =TRUE)) |>ungroup()# Tag CBSAs based on the four rubric criteriayimby_analysis <- yimby_metrics |>mutate(yimby_score =ifelse(early_burden >median(early_burden, na.rm =TRUE) &burden_change <0&pop_growth >0&avg_housing_growth >median(avg_housing_growth, na.rm =TRUE),"YIMBY Success", "Other"))# Collapse to one row per CBSA for summary/plotsyimby_summary <- yimby_analysis |>distinct(City_Name, .keep_all =TRUE)# Four rubric criteria flagsyimby_flags <- yimby_summary |>mutate(high_early = early_burden >median(early_burden, na.rm =TRUE),improved = burden_change <0,grew = pop_growth >0,above_avg_growth = avg_housing_growth >median(avg_housing_growth, na.rm =TRUE),is_success_all4 = high_early & improved & grew & above_avg_growth)# Helpers for inline textyimby_success_names <- yimby_flags |>filter(is_success_all4) |>arrange(burden_change) |>pull(City_Name)yimby_success_n <-length(yimby_success_names)yimby_success_preview <-paste(head(yimby_success_names, 5), collapse =", ")
7.1 Rent Burden vs Housing Growth
Code
library(ggplot2)ggplot(yimby_summary,aes(x = burden_change, y = avg_housing_growth, color = yimby_score)) +geom_point(alpha =0.6, size =2) +scale_color_manual(values =c("YIMBY Success"="#2E8B57", "Other"="gray70")) +labs(title ="Rent Burden Change vs Housing Growth",subtitle ="Cities with strong housing growth tend to see rent burden improvements",x ="Change in Rent Burden (percentage points)",y ="Average Housing Growth Score",color ="Metro Type") +theme_minimal(base_size =14) +theme(plot.title =element_text(face ="bold"),plot.subtitle =element_text(size =11, color ="gray40"),legend.position ="bottom",panel.grid.minor =element_blank())
Cities shown in green (“YIMBY Success”) built more housing and saw rent burdens stabilize or decline over time.
This pattern supports the idea that steady housing production helps prevent rent spikes, even in growing metros.
7.2 Population Growth vs Housing Affordability
Code
ggplot(yimby_summary,aes(x = pop_growth, y =-burden_change, color = yimby_score)) +geom_point(alpha =0.6, size =2) +scale_color_manual(values =c("YIMBY Success"="#457B9D", "Other"="gray70")) +labs(title ="Population Growth vs Rent Burden Improvement",subtitle ="Higher population growth with lower rent burden indicates strong housing supply response",x ="Population Growth (%)",y ="Rent Burden Improvement (percentage points)",color ="Metro Type") +theme_minimal(base_size =14) +theme(plot.title =element_text(face ="bold"),plot.subtitle =element_text(size =11, color ="gray40"),legend.position ="bottom",panel.grid.minor =element_blank())
Many metros with strong population growth also achieved better affordability when new housing kept pace.
In contrast, regions with low construction saw rent burdens worsen — highlighting how growth without supply drives up costs.
7.3 Metros Achieving Affordability Through Construction
Table: Metropolitan Areas Improving Affordability Through Housing Supply (Top 10)
These metros represent the top 10 “YIMBY success stories” cities that started with relatively high rent burdens but achieved improvements over time while maintaining strong housing growth.
The leading metro, New Bern, NC Metro Area, saw a rent burden drop of 1.9 percentage points while maintaining a housing growth score of 34.9.
This demonstrates how steady new construction helps stabilize affordability even as populations rise.
The table highlights two contrasting metros that capture both success and need in housing reform.
The primary sponsor city, New Bern, NC Metro Area, achieved a rent burden decline of 1.9 percentage points and strong housing growth (34.9 score), proving that steady permitting can reduce affordability pressures.
The co-sponsor city, Miami-Fort Lauderdale-West Palm Beach, FL Metro Area, saw rent burden rise to 30.1% with limited housing growth (4.4 score), showing the cost of underbuilding.
Together, these cities make a compelling case for federal incentives that expand local housing capacity while maintaining affordability.
Code
# Map WAGES CBSA to names using POPULATION cbsa_map <- POPULATION %>%distinct(GEOID, NAME) %>%mutate(std_cbsa =paste0("C", GEOID)) %>%select(std_cbsa, NAME)# Join wage data with metro names for readabilitywages_named <- WAGES %>%mutate(std_cbsa =paste0(FIPS, "0")) %>%inner_join(cbsa_map, by ="std_cbsa")# Filter for target metros and industries, then summarizetwo_metros <- wages_named %>%filter(NAME %in%c(primary_name, cosponsor_name), INDUSTRY %in%c(23, 62)) %>%group_by(NAME, INDUSTRY) %>%summarise(Employment =sum(EMPLOYMENT, na.rm =TRUE),`Avg Annual Wage (USD)`=round(weighted.mean(AVG_WAGE, w = EMPLOYMENT, na.rm =TRUE), 0),.groups ="drop" ) %>%mutate(Industry = dplyr::case_when( INDUSTRY ==23~"Construction (NAICS 23)", INDUSTRY ==62~"Health Care & Social Assistance (NAICS 62)",TRUE~paste0("NAICS ", INDUSTRY) )) %>%select(Industry, Metro = NAME, Employment, `Avg Annual Wage (USD)`)
8Policy Brief: A National Framework for Housing Affordability
MEMORANDUM
TO: Interested Members of Congress FROM: Housing Policy Analyst DATE: October 26, 2023 SUBJECT: The Need for Federal Incentives to Encourage Steady Local Housing Construction
1. Issue Overview
Rent burdens remain critically high across U.S. metropolitan areas, undermining household financial security and regional economic stability. This crisis persists even amid rising incomes and job growth, indicating a fundamental failure of housing supply to meet demand.
2. Key Findings
Data reveals a clear solution: metropolitan areas that maintain a consistent pipeline of new housing construction successfully lower rent burdens without negatively impacting population or job growth. The current challenge is that local permitting is often volatile, leading to short-term construction spikes rather than the steady, multi-year supply needed to stabilize markets.
3. Policy Recommendation
Congress should establish a federal incentive program that rewards local governments for sustaining higher rates of housing production. This program would use a composite metric to evaluate success, combining:
Current Construction Activity: Housing permits per 1,000 residents.
Responsive Growth: Whether permit issuance has kept pace with population growth over a five-year period.
4. Evidence for Action
The success of this approach is demonstrated by the contrasting outcomes in two metropolitan areas:
New Bern, NC Metro Area (Model for Success): By prioritizing consistent housing permits, this metro reduced its rent burden from 22.2% to 20.4% while its population grew 6.1%. This proves affordability is achievable alongside growth.
Miami-Fort Lauderdale-West Palm Beach, FL Metro Area (Case for Intervention): This city, where housing supply has lagged, saw its rent burden rise from 28.6% to 30.1% despite minimal population growth. It exemplifies the regions this bill is designed to help.
5. Coalition of Support
A federal incentive for housing production will build a powerful coalition, receiving strong support from major industries that benefit from stable housing markets:
Construction: Predictable permitting creates steady, skilled jobs. In New Bern, NC Metro Area, this sector employs over 1,595,772 workers with average wages of $54,289, while in Miami-Fort Lauderdale-West Palm Beach, FL Metro Area, it provides 14,900 jobs.
Health Care & Social Assistance: Affordable housing is key to retaining essential frontline staff. This sector employs 4,292,849 workers in New Bern, NC Metro Area and 53,721 in Miami-Fort Lauderdale-West Palm Beach, FL Metro Area—demonstrating its critical role in both regional and rural economies.
Conclusion
Housing affordability improves when cities build steadily, not sporadically.
This analysis shows that consistent permitting, supported by smart federal incentives, can help every metro area balance growth with livability.
By rewarding results and empowering local governments to build, this bill moves the nation from housing shortage to housing stability.